import { addTreePropertyForList, deepCloneV2, defaultDocConfig, defaultDocExtraConfigInfo, deleteNodeAndMoveChildren, dfsRecursive, filterTree, generateTreeData, getUuid, isEmpty, parsePrice, protectlandLevelList, provinceList, toastShort, tree2List } from "../../../utils";
import { DocConfig, DocInstance, PlanningBasisType, DocItemChangeRecord, TopicType, WordParagraphBlock, TopicCheckedStatus } from "../../../utils/types";
import { DocItem, DocItemType, SlateEditorInputInfo } from "../../slate-editor";
import { initMergeCellBoundGroup, initTableHeader } from "../excel-editor/initData";
import { initOrUpdateSystemChapter } from "./system-chapter";
import { initExcelBuninessContentForWorker } from "../../../utils/workerUtils";
import { convertNewTableDataToGridTableData } from "../excel-editor/ExcelEditorHelper";
import { TableDataCell } from "../../../types";
import { AlignEnum } from "../../slate-editor/constants";
import { isPresetresetDocItemTextTopicName, presetDocItemText } from "./preset-doc-Item-text";
import { generateScheduleTableAdditionalDocItemList } from "./schedule-doc-item-list";

type DocInstanceAssemblyStatus = 'Uninitialized' | 'Initialized';

const getTitleParagraphLevel = (topic: TopicType): DocItemType => {
    let titleParagraphLevel: DocItemType = DocItemType.H1;
    if (
        isEmpty(topic.topicLevel) ||
        topic.topicLevel == undefined ||
        //@ts-ignore
        topic.topicLevel == "undefined"
    ) {
        topic.topicLevel = '3'
    } else {
        if (Number(topic.topicLevel) > 6) {
            topic.topicLevel = '6';
        }
    }
    switch (topic.topicLevel) {
        case '1':
            titleParagraphLevel = DocItemType.H1;
            break;
        case '2':
            titleParagraphLevel = DocItemType.H2;
            break;
        case '3':
            titleParagraphLevel = DocItemType.H3;
            break;
        case '4':
            titleParagraphLevel = DocItemType.H4;
            break;
        case '5':
            titleParagraphLevel = DocItemType.H5;
            break;
        case '6':
            titleParagraphLevel = DocItemType.H6;
            break;
        default:
            break;
    }
    return titleParagraphLevel;
}

/**
 * 收集textTopic下的背景文本
 * @param textTopic 
 */
const collectTextTopicBackgroundParagraph = (textTopic: TopicType): string[] => {
    const backgroundParagraphList: string[] = [];
    if (!isEmpty(textTopic.backgroundParagraph1)) {
        backgroundParagraphList.push(textTopic.backgroundParagraph1)
    }
    if (!isEmpty(textTopic.backgroundParagraph2)) {
        backgroundParagraphList.push(textTopic.backgroundParagraph2)
    }
    if (!isEmpty(textTopic.backgroundParagraph3)) {
        backgroundParagraphList.push(textTopic.backgroundParagraph3)
    }
    if (!isEmpty(textTopic.backgroundParagraph4)) {
        backgroundParagraphList.push(textTopic.backgroundParagraph4)
    }
    return backgroundParagraphList;
}

/**
 * 随机抽取
 * @param paragraphList 
 * @returns 
 */
const getRadomParagraphPlainText = (
    paragraphList: string[]
): { randomText: string, randomIndex: number } => {
    let randomText: string = '';
    const len = paragraphList.length;
    if (len == 0) {
        randomText = '';
    }
    const randomIndex = Math.floor(Math.random() * len);
    randomText = paragraphList[randomIndex];
    return {
        randomIndex,
        randomText
    };
}

const adaptProtectlandLevel = (level) => {
    const protectlandLevel = protectlandLevelList.find(ele => {
        return ele.value == level;
    })
    return protectlandLevel ? protectlandLevel.label : '未知等级';
}

/**
 * 
 * @param type 
 * @param subType 
 * @returns 
 */
const getprotectlandTypeReg2 = (type: string, subType: string) => {
    let str = '';
    switch (type) {
        case '国家公园':
            str = '国家公园'
            break;
        case '自然保护区':
            str = '保护区'
            break;
        case '自然公园':
            switch (subType) {
                case '森林公园':
                    str = '森林公园';
                    break;
                case '地质公园':
                    str = '地质公园';
                    break;
                case '湿地公园':
                    str = '湿地公园';
                    break;
                case '草原公园':
                    str = '草原公园';
                    break;
                case '海洋公园':
                    str = '海洋公园';
                    break;
                case '沙漠公园':
                    str = '沙漠公园';
                    break;
                case '风景名胜区':
                    str = '风景名胜区';
                    break;
                default:
                    break;
            }
            break;
        default:
            str = type;
            break;
    }
    return str;
}

/**
 * 
 * @param originText 
 * @param docInstance 
 * @returns 
 */
const getReplacedDocInfoPlainText = (
    originText: string,
    docInstance: DocInstance
): string => {
    if (isEmpty(originText)) {
        originText = '';
    }
    const {
        protectland: {
            type,
            subType,
        },
        protectlandBaseInfo: {
            protectlandArea,
            protectlandAreaUnit = '公顷',
            protectlandLevel,
            protectlandName,
            protectlandProvince,
            protectlandTypeId,
            startYear,
            endYear
        }
    } = docInstance;
    let _protectlandAreaUnit = protectlandAreaUnit;
    _protectlandAreaUnit = _protectlandAreaUnit.replace("km2", "km²")
    if (isEmpty(_protectlandAreaUnit)) {
        _protectlandAreaUnit = '公顷';
    }
    let nameReg1 = /\[name\]/gi;
    let areaRg1 = /\[area公顷\]/gi;
    let areaRg2 = /\[area\]/gi;
    let startYearReg1 = /YS\+1/gi;
    let startYearReg2 = /YS\+2/gi;
    let startYearReg3 = /YS\+3/gi;
    let startYearReg4 = /YS\+4/gi;
    let startYearReg5 = /YS\+5/gi;
    let startYearReg = /YS/gi;
    let endYearReg1 = /YF\+1/gi;
    let endYearReg2 = /YF\+2/gi;
    let endYearReg3 = /YF\+3/gi;
    let endYearReg4 = /YF\+4/gi;
    let endYearReg5 = /YF\+5/gi;
    let endYearReg = /YF/gi;
    originText = originText.replace(nameReg1, protectlandName);
    originText = originText.replace(areaRg1, protectlandArea + _protectlandAreaUnit);
    originText = originText.replace(areaRg2, protectlandArea + _protectlandAreaUnit);
    let provinceReg = /\[p\]/gi;
    const findProtectlandProvince = provinceList.find(ele => {
        return ele.label == protectlandProvince;
    });
    const provinceSuffix = findProtectlandProvince ? findProtectlandProvince.suffix : ''
    originText = originText.replace(provinceReg, protectlandProvince ? protectlandProvince + provinceSuffix : '【地理信息缺失】');
    let protectlandTypeReg1 = /\[type\]/gi;
    let protectlandTypeReg2 = /\[\*\]/g;
    originText = originText.replace(protectlandTypeReg1, type ? `“${subType}”类型的${adaptProtectlandLevel(protectlandLevel)}${type}` : '【地理信息缺失】');
    originText = originText.replace(protectlandTypeReg2, type ? getprotectlandTypeReg2(type, subType) : '');
    originText = originText.replace(startYearReg1, (new Date(startYear).getFullYear() + 1) + '');
    originText = originText.replace(startYearReg2, (new Date(startYear).getFullYear() + 2) + '');
    originText = originText.replace(startYearReg3, (new Date(startYear).getFullYear() + 3) + '');
    originText = originText.replace(startYearReg4, (new Date(startYear).getFullYear() + 4) + '');
    originText = originText.replace(startYearReg5, (new Date(startYear).getFullYear() + 5) + '');
    originText = originText.replace(startYearReg, new Date(startYear).getFullYear() + '');
    originText = originText.replace(endYearReg1, (new Date(endYear).getFullYear() + 1) + '');
    originText = originText.replace(endYearReg2, (new Date(endYear).getFullYear() + 2) + '');
    originText = originText.replace(endYearReg3, (new Date(endYear).getFullYear() + 3) + '');
    originText = originText.replace(endYearReg4, (new Date(endYear).getFullYear() + 4) + '');
    originText = originText.replace(endYearReg5, (new Date(endYear).getFullYear() + 5) + '');
    originText = originText.replace(endYearReg, new Date(endYear).getFullYear() + '');
    originText = originText.replace(/\\n/g, '');
    return originText;
}

/**
 * 生成段落ID
 * @param baseId 
 * @param tag 
 * @returns 
 */
const generateDocItemId = (
    baseId: string,
    tag: DocItemType | 'h' | 'p' | 'cp' | 'sys'
) => {
    // return `${baseId}-${tag}-${getUuid(8)}`
    return `${baseId}-${tag}`
}


/**
 * 向下选中
 * @param docInstance 
 */
const associationTopicTreeNodeChecked = (
    topicTreeData: TopicType[]
): TopicType[] => {
    let tempTopicTreeData: TopicType[] = deepCloneV2(topicTreeData);
    //处理上下级选中联动管理，排除下级有设施设备节点的问题
    dfsRecursive(topicTreeData, (topic: TopicType, level: number) => {
        if (topic.topicType == 'text') {
            let hasIncludeDeviceTopic = false;
            dfsRecursive(topic.children ? topic.children : [], (childTopic: TopicType) => {
                if (childTopic.topicType == 'device' && childTopic.checked) {
                    hasIncludeDeviceTopic = true;
                }
            })
            topic.hasIncludeDeviceTopic = hasIncludeDeviceTopic;
        }
    })
    return deepCloneV2(tempTopicTreeData);
}

/**
 * 检查某一节点是否包含设备节点/或者其本身是否是设备节点
 * @param topic 
 * @returns 
 */
const checkTextTopicHasDeviceChildTopic = (topic: TopicType): boolean => {
    try {
        let hasDeviceChildTopic = false;
        if (topic.topicType === 'text') {
            if (topic.children && topic.children.length) {
                topic.children.forEach(item => {
                    if (item.topicType == 'device') {
                        hasDeviceChildTopic = true;
                    }
                })
                if (!hasDeviceChildTopic) {
                    topic.children.forEach(ele => {
                        if (checkTextTopicHasDeviceChildTopic(ele)) {
                            hasDeviceChildTopic = true;
                        }
                    })
                }
            }
        } else {
            hasDeviceChildTopic = true;
        }
        return hasDeviceChildTopic;
    } catch (e) {
        toastShort("error", "checkTextTopicHasDeviceChildTopic-err" + e)
        return false;
    }
}

/**
 * 获取topic实际选中状态
 * @param topic 
 * @returns 
 */
const getTopicNodeChckedStatus = (
    topic: TopicType
): TopicCheckedStatus => {
    return topic.realCheckedStatus;
    // let checkedStatus: TopicCheckedStatus = 'noChecked';
    // if (topic.checked) {
    //     checkedStatus = 'checked';
    // } else if (topic.children && topic.children.length) {
    //     let hasChildTopicChecked = false;
    //     dfsRecursive(topic.children, (childTopic: TopicType) => {
    //         if (childTopic.checked) {
    //             hasChildTopicChecked = true;
    //         }
    //     })
    //     if (hasChildTopicChecked) {
    //         checkedStatus = 'halfChecked'
    //     }
    // }
    // return checkedStatus;
}

/**
 * 选中关联状态检查
 * @param docInstance 
 * @returns 
 */
const checkTopicNodeBeforeInitalization = (
    docInstance: DocInstance
): DocInstance => {
    try {
        const {
            protectlandBaseInfo: {
                protectlandProblemList,
                protectlandTypeId,
                type,
                subType
            },
            topicList
        } = docInstance;
        let tempDocInstance = docInstance;
        let tempTopicList: TopicType[] = topicList;
        tempTopicList.forEach(topic => {
            topic.topicName = getReplacedDocInfoPlainText(topic.topicName, docInstance);
            let checked = false;
            if (!isEmpty(topic.checked)) {
                checked = topic.checked;
            }
            if (topic.topicType == 'device') {
                if (topic.defaultRecommand) {
                    //如果默认推荐
                    checked = true;
                } else {
                    if (
                        topic.protectlandProblemList &&
                        topic.protectlandProblemList.length &&
                        protectlandProblemList.length
                    ) {
                        let matchProblem = false;
                        topic.protectlandProblemList.forEach(ele => {
                            const protectlandProblemListStr = protectlandProblemList[0];
                            const protectlandProblemValueList = protectlandProblemListStr.split(',');
                            //@ts-ignore
                            ele.forEach(value => {
                                if (protectlandProblemValueList.includes(value)) {
                                    matchProblem = true;
                                }
                            })
                        })
                        if (matchProblem) {
                            checked = true;
                        }
                    }
                    if (
                        topic.protectlandTypeIdList &&
                        topic.protectlandTypeIdList.length
                    ) {
                        const protectlandTypeIdList = topic.protectlandTypeIdList;
                        protectlandTypeIdList.forEach(protectlandType => {
                            if (protectlandType[0] == type) {
                                if (protectlandType[1] == subType) {
                                    checked = true;
                                }
                            }
                        })
                    }
                }
            }
            //TODO 根据后台后续规则继续推荐数量、单价
            topic.checked = checked;
        })
        let topicTreeData = generateTreeData(addTreePropertyForList(tempTopicList));
        //处理文本大纲节点默认推荐
        dfsRecursive(topicTreeData, (topic: TopicType, level: number) => {
            let checked = topic.checked;
            if (topic.topicType == 'text') {
                const hasDeviceChildTopic = checkTextTopicHasDeviceChildTopic(topic);
                if (hasDeviceChildTopic) {
                    //@ts-ignore
                    topic.checked = null;
                } else if (topic.defaultRecommand) {
                    checked = true;
                }
            }
            topic.checked = checked;
        })
        topicTreeData = associationTopicTreeNodeChecked(topicTreeData);
        tempTopicList = tree2List(topicTreeData);
        tempDocInstance.topicList = deepCloneV2(tempTopicList);
        return deepCloneV2(tempDocInstance);
    } catch (e) {
        console.error("初始化前勾选节点失败--->", e)
    }
}

/**
 * 
 * @param tree 
 */
const findHasFullCheckedChildNode = (tree: TopicType[]): boolean => {
    let hasFullCheckedChildNode: boolean = false;
    tree.forEach(node => {
        if (node.checked) {
            hasFullCheckedChildNode = true;
        }
        // if(node.title == "科研监测目标"){
        //     console.log("科研监测目标---->", node.checked, hasFullCheckedChildNode)
        // }
    })
    if (!hasFullCheckedChildNode) {
        // console.log("")
        tree.forEach(node => {
            if (node.children && node.children.length) {
                let tempHasFullCheckedChildNode = findHasFullCheckedChildNode(node.children);
                if (tempHasFullCheckedChildNode) {
                    hasFullCheckedChildNode = true;
                }
            }
        })
    }
    return hasFullCheckedChildNode;
}

/**
 * 更新 topic的实际
 * @param tempTopicTreeData 
 */
const updateTopicRealCheckedStatus = (
    tempTopicTreeData: TopicType[]
): TopicType[] => {
    dfsRecursive(tempTopicTreeData, (topic: TopicType, level: number) => {
        if (topic.topicType == 'text') {
            if (topic.checked) {
                topic.realCheckedStatus = "fullChecked";
            } else if (topic.children && findHasFullCheckedChildNode(topic.children)) {
                topic.realCheckedStatus = "halfChecked";
            } else {
                topic.realCheckedStatus = "noChecked";
            }
            // if (topic.topicName === "规划主要内容") {
            //     const test = findHasFullCheckedChildNode(topic.children);
            //     console.log("test--->", test, deepCloneV2(topic))
            // }
        } else {
            topic.realCheckedStatus = topic.checked ? "fullChecked" : "noChecked";
        }
    })
    return tempTopicTreeData;
}

/**
 * 更新实际的编号, 以及topicLevel
 * @param tempTopicTreeData 
 * @returns 
 */
const initOrUpdateTopicTreeDataSerialNumber = (
    tempTopicTreeData: TopicType[]
): TopicType[] => {
    let serialNumberList: number[] = [];
    let serialNumberListByChecked: number[] = [];
    tempTopicTreeData = updateTopicRealCheckedStatus(tempTopicTreeData);
    //不要在这里实施过滤
    // tempTopicTreeData = filterTree(tempTopicTreeData, (node) => node.realCheckedStatus !== 'noChecked');
    // console.log("过滤后的--->", tempTopicTreeData)
    dfsRecursive(tempTopicTreeData, (topic: TopicType, level: number) => {
        if (topic.topicType == 'text') {
            if (serialNumberList.length > level) {
                serialNumberList = serialNumberList.splice(0, level + 1)
                serialNumberList[serialNumberList.length - 1]++;
            } else if (serialNumberList.length == level) {
                if (isEmpty(serialNumberList[level])) {
                    serialNumberList[level] = 1;
                } else {
                    serialNumberList[level]++;
                }
            } else {
                serialNumberList.push(1)
            }
            const serialNumber = serialNumberList.join('.');
            topic.serialNumber = serialNumber;
            topic.topicLevel = level + 1 + '';
            topic.treeLevel = level;  //暂时没用到
            //
            const topicNodeCheckedStatus = getTopicNodeChckedStatus(topic);
            if (topicNodeCheckedStatus !== 'noChecked') {
                if (serialNumberListByChecked.length > level) {
                    serialNumberListByChecked = serialNumberListByChecked.splice(0, level + 1)
                    serialNumberListByChecked[serialNumberListByChecked.length - 1]++;
                } else if (serialNumberListByChecked.length == level) {
                    if (isEmpty(serialNumberListByChecked[level])) {
                        serialNumberListByChecked[level] = 1;
                    } else {
                        serialNumberListByChecked[level]++;
                    }
                } else {
                    serialNumberListByChecked.push(1)
                }
                const serialNumberByChecked = serialNumberListByChecked.join('.');
                topic.serialNumberByChecked = serialNumberByChecked;
            }
        }

    })
    return tempTopicTreeData;
}

/**
 * 组装文本节点标题段落
 * @param textTopic 
 */
const assemblyTextTopicTitleParagraph = (
    textTopic: TopicType
): DocItem => {
    let titleParagraph: DocItem = {
        id: '',
        type: DocItemType.H1,
        text: '',
        data: {},
        textStyleMap: {},
        style: {},
    };
    const titleParagraphDocItemType = getTitleParagraphLevel(textTopic);
    const titlePragraphDataIndex = titleParagraphDocItemType == DocItemType.H1 ? `第 ${textTopic.serialNumberByChecked} 章` : `${textTopic.serialNumberByChecked}`;
    titleParagraph.id = generateDocItemId(textTopic.id, 'h');
    titleParagraph.type = titleParagraphDocItemType;
    titleParagraph.text = `${textTopic.topicName}`;
    titleParagraph.data = {
        '$[INDEX]': titlePragraphDataIndex,
    };
    switch (titleParagraphDocItemType) {
        case DocItemType.H1:
            titleParagraph.style.align = AlignEnum.center;
            titleParagraph.textStyleMap = {
                '$$[1]': {
                    "heading": 1,
                    "fontSize": "17.1pt",
                    "fontFamily": "SimHei",
                    "bold": true,
                    "text": titleParagraph.text,
                    "lineHeight": 1.5,
                }
            }
            break;
        case DocItemType.H2:
            titleParagraph.style.align = AlignEnum.left;
            titleParagraph.textStyleMap = {
                '$$[1]': {
                    "text": titleParagraph.text,
                    "heading": 2,
                    "fontSize": "17.1pt",
                    "fontFamily": "SimHei",
                    "bold": true,
                    "lineHeight": 2.5,
                }
            }
            break;
        case DocItemType.H3:
            titleParagraph.style.align = AlignEnum.left;
            titleParagraph.textStyleMap = {
                '$$[1]': {
                    "text": titleParagraph.text,
                    "heading": 3,
                    "fontSize": "15pt",
                    "fontFamily": "SimHei",
                    "bold": true,
                    "lineHeight": 1.5,
                }
            }
            break;
        case DocItemType.H4:
            titleParagraph.style.align = AlignEnum.left;
            titleParagraph.textStyleMap = {
                '$$[1]': {
                    "text": titleParagraph.text,
                    "heading": 4,
                    "fontSize": "15pt",
                    "fontFamily": "SimHei",
                    "bold": true,
                    "lineHeight": 1,
                }
            }
            break;
        case DocItemType.H5:
            titleParagraph.style.align = AlignEnum.left;
            titleParagraph.textStyleMap = {
                '$$[1]': {
                    "text": titleParagraph.text,
                    "heading": 5,
                    "fontSize": "12.8pt",
                    "fontFamily": "SimHei",
                    "bold": true,
                    "lineHeight": 1,
                    "textIndent": "1em",
                }
            }
            break;
        case DocItemType.H6:
            titleParagraph.style.align = AlignEnum.left;
            titleParagraph.textStyleMap = {
                '$$[1]': {
                    "text": titleParagraph.text,
                    "heading": 6,
                    "fontSize": "12.8pt",
                    "fontFamily": "SimHei",
                    "bold": true,
                    "lineHeight": 1,
                    "textIndent": "1em",
                }
            }
            break;
        default:
            titleParagraph.style.align = AlignEnum.left;
            titleParagraph.textStyleMap = {
                '$$[1]': {
                    "text": titleParagraph.text,
                }
            }
            break;
    }
    titleParagraph.text = '$$[1]';
    return titleParagraph;
}

/**
 * 组装背景文本段落
 * @param textTopic 
 * @param docInstance 
 */
const assemblyTextTopicBackgroundParagraph = (
    textTopic: TopicType,
    docInstance: DocInstance
): {
    newTextTopic: TopicType,
    backgroundParagraphDocItem: DocItem
} => {
    let backgroundParagraphDocItem: DocItem = {
        id: '',
        type: DocItemType.P,
        text: '',
        style: {
            align: AlignEnum.justify,
        },
        data: {}
    };
    let backgroundParagraphList: string[] = collectTextTopicBackgroundParagraph(textTopic);
    //如果有背景文本需要生成
    if (backgroundParagraphList.length) {
        //随机抽取背景文本
        let {
            randomIndex,
            randomText
        } = getRadomParagraphPlainText(backgroundParagraphList);
        //替换当前规划信息
        const currentBackgroundParagraphPlainText = getReplacedDocInfoPlainText(randomText, docInstance);
        //标记当前随机使用的是哪个背景文本
        textTopic.currentInUseBackgroundParagraphIndex = randomIndex;
        // console.log("textTopic.currentInUseBackgroundParagraphIndex--->", textTopic.currentInUseBackgroundParagraphIndex)
        //根据换行符分割背景文本(新版本暂时不需要这样处理,编辑器内部处理了换行符)
        // const backgroundParagraphSliceList = currentBackgroundParagraphPlainText.split(/[(\r\n)\r\n]+/);
        backgroundParagraphDocItem.id = generateDocItemId(textTopic.id, 'p');
        backgroundParagraphDocItem.type = DocItemType.P;
        backgroundParagraphDocItem.text = currentBackgroundParagraphPlainText;
        backgroundParagraphDocItem.plainText = currentBackgroundParagraphPlainText;
    }
    backgroundParagraphDocItem = highlightReminderDocItem(backgroundParagraphDocItem);
    return {
        newTextTopic: textTopic,
        backgroundParagraphDocItem
    };
}

/**
 * 高亮#文本#标记
 * @param docItem 
 * @returns 
 */
const highlightReminderDocItem = (docItem: DocItem): DocItem => {
    const pattern = /#(.*?)#/g;
    let index = 0;
    const textStyleMap = {};
    let transformedText = docItem.text;
    const originalText = docItem.text;
    transformedText = originalText.replace(pattern, (match, p1) => {
        const placeholder = `$$[${index}]`;
        textStyleMap[placeholder] = {
            text: p1,
            bgColor: '#ffec3d',
            highlightReminder: true
        };
        index++;
        return placeholder;
    });
    docItem.textStyleMap = textStyleMap;
    docItem.text = transformedText;
    return docItem;
}


interface DeviceParagraphGroup {
    deviceGroupType: 'S' | 'X'
    deviceTopicList: TopicType[]
    facilitiesBackgroundParagraphPlainText?: string
    deviceBackgroundParagraphPlainText?: string
}

/**
 * 
 * @param deviceTopicList 
 * @param docInstance 
 * @returns 
 */
const collectDeviceParagraphGroup = (
    deviceTopicList: TopicType[],
    docInstance: DocInstance
): DeviceParagraphGroup[] => {
    let deviceParagraphGroup: DeviceParagraphGroup[] = [];
    deviceTopicList.forEach((deviceTopic, index) => {
        if (deviceTopic.deviceType == 'S') {
            const facilitiesBackgroundParagraphList: string[] = [];  //当前设施的设施文本
            //设施文本
            if (!isEmpty(deviceTopic.facilitiesBackgroundParagraph1)) {
                facilitiesBackgroundParagraphList.push(deviceTopic.facilitiesBackgroundParagraph1);
            }
            if (!isEmpty(deviceTopic.facilitiesBackgroundParagraph2)) {
                facilitiesBackgroundParagraphList.push(deviceTopic.facilitiesBackgroundParagraph2);
            }
            if (!isEmpty(deviceTopic.facilitiesBackgroundParagraph3)) {
                facilitiesBackgroundParagraphList.push(deviceTopic.facilitiesBackgroundParagraph3);
            }
            if (!isEmpty(deviceTopic.facilitiesBackgroundParagraph4)) {
                facilitiesBackgroundParagraphList.push(deviceTopic.facilitiesBackgroundParagraph4);
            }
            //TODO 构建默认
            if (facilitiesBackgroundParagraphList.length == 0) {
                facilitiesBackgroundParagraphList.push("规划配置")
            }
            const {
                randomIndex,
                randomText
            } = getRadomParagraphPlainText(facilitiesBackgroundParagraphList);
            deviceParagraphGroup.push({
                deviceGroupType: 'S',
                facilitiesBackgroundParagraphPlainText: randomText,
                deviceTopicList: [deviceTopic]
            })
        } else {
            const deviceBackgroundParagraphList: string[] = [];      //当前设备的背景文本
            let currentDeviceBackgroundParagraph: string = "";       //随机选中的设备的背景文本
            let deviceConstituteParagraph: string = "";              //设备结构文本
            //设备背景文本
            if (!isEmpty(deviceTopic.deviceBackgroundParagraph1)) {
                deviceBackgroundParagraphList.push(deviceTopic.deviceBackgroundParagraph1);
            }
            if (!isEmpty(deviceTopic.deviceBackgroundParagraph2)) {
                deviceBackgroundParagraphList.push(deviceTopic.deviceBackgroundParagraph2);
            }
            if (!isEmpty(deviceTopic.deviceBackgroundParagraph3)) {
                deviceConstituteParagraph = deviceTopic.deviceBackgroundParagraph3;
            }
            const {
                randomIndex,
                randomText
            } = getRadomParagraphPlainText(deviceBackgroundParagraphList);
            currentDeviceBackgroundParagraph = randomText;
            if (
                deviceParagraphGroup[deviceParagraphGroup.length - 1] &&
                deviceParagraphGroup[deviceParagraphGroup.length - 1].deviceGroupType == 'X' &&
                (
                    //如果这是设施、且它的设施文本与最近的一条
                    deviceParagraphGroup[deviceParagraphGroup.length - 1].deviceBackgroundParagraphPlainText == currentDeviceBackgroundParagraph ||
                    //或者设备问题是空的
                    isEmpty(currentDeviceBackgroundParagraph)
                )
            ) {
                deviceParagraphGroup[deviceParagraphGroup.length - 1].deviceTopicList.push(deviceTopic);
            } else {
                deviceParagraphGroup.push({
                    deviceGroupType: 'X',
                    deviceBackgroundParagraphPlainText: currentDeviceBackgroundParagraph,
                    deviceTopicList: [deviceTopic]
                })
            }
        }
    })
    return deviceParagraphGroup;
}

const splitDeviceParagraph = (deviceParagraph: string): string[] => {
    const pattern = /(\$?\[[^\]]+\]|YS\+?[1-5]?|YF\+?[1-5]?|YF-YS\+1)/;
    const deviceParagraphSlice: string[] = deviceParagraph.split(pattern).filter((item) => item);
    return deviceParagraphSlice.length ? deviceParagraphSlice : ["$[X]", "$[N]", "$[U]"];
}

/**
 * 
 * @param matchingCharacter 
 * @param docInstance 
 * @param deviceTopic 
 * @returns 
 */
const getSlateEditorInputShowText = (
    matchingCharacter: string,
    docInstance: DocInstance,
    deviceTopic: TopicType
): string => {
    const {
        protectland: {
            type,
            subType
        },
        protectlandBaseInfo: {
            protectlandArea,
            protectlandAreaUnit,
            protectlandLevel,
            protectlandName,
            protectlandProvince,
            protectlandTypeId
        }
    } = docInstance;
    let entityText: string = "";
    switch (matchingCharacter) {
        case '[*]':
        case '$[*]':
            entityText = getprotectlandTypeReg2(type, subType);
            break;
        case '[NAME]':
        case '$[NAME]':
            entityText = protectlandName;
            break;
        case '[P]':
        case '$[P]':
            entityText = protectlandProvince + '省';
            break;
        case '[type]':
        case '$[type]':
            entityText = `“${subType}”类型的${adaptProtectlandLevel(protectlandLevel)}${type}`;
            break;
        case '$[S]':
        case '$[X]':
            entityText = deviceTopic.topicName;
            break;
        case '$[N]':
            entityText = deviceTopic.count;
            break;
        case '$[U]':
            entityText = deviceTopic.unit;
            break;
        default:
            break;
    }
    return entityText + '';
}

/**
 * 构造不重复的段落输入框标记
 * @param attr 
 * @param index 
 * @returns 
 */
const serializationDeviceAttr = (attr: string, tag: string): string => {
    if (attr.length === 0) {
        return attr;
    }
    let partBeforeLastChar = attr.slice(0, -1);
    let lastChar = attr.slice(-1);
    return (partBeforeLastChar + tag + lastChar).toString();
    // return (partBeforeLastChar + tag + lastChar).toString().replace('$', '');
}

/**
 * 组装文本节点下的设施设备节点
 * @param textTopic 
 * @param docInstance 
 */
const assemblyPureDeviceChildTopicParagraph = (
    textTopic: TopicType,
    docInstance: DocInstance
): DocItem => {
    try {
        let paragraphDocItem: DocItem = {
            id: '',
            type: DocItemType.P,
            text: '',
            data: {},
            style: {
                align: AlignEnum.justify,
            },
            externalData: {}
        };
        let childTopicIdSortList = [];
        let checkedPureDeviceTopicList: TopicType[] = [];
        textTopic.children && textTopic.children.forEach(deviceTopic => {
            if (
                deviceTopic.checked &&
                deviceTopic.topicType == 'device' &&
                !deviceTopic.isUnionTopic  //必须不是合并类型
            ) {
                checkedPureDeviceTopicList.push(deviceTopic);
            }
        })
        let deviceParagraphPlainText = '';
        let deviceParagraphDocItemData = {};
        childTopicIdSortList = checkedPureDeviceTopicList.map(item => {
            return item.id;
        })
        paragraphDocItem.externalData['childTopicIdSortList'] = childTopicIdSortList;
        const deviceParagraphGroupList: DeviceParagraphGroup[] = collectDeviceParagraphGroup(checkedPureDeviceTopicList, docInstance);
        if (textTopic.topicName === "防火监测预警") {
            console.log("deviceParagraphGroupList--->", deviceParagraphGroupList)
        }
        deviceParagraphGroupList.forEach((deviceParagraphGroup, deviceParagraphGroupIndex) => {
            //如果是设施节点
            if (deviceParagraphGroup.deviceGroupType == 'S') {
                //设施节点一般只有1个，形成 1设施带多设备的段落
                const currentDeviceTopic = deviceParagraphGroup.deviceTopicList[0];
                if (deviceParagraphGroup.deviceTopicList.length > 1) {
                    toastShort("warning", "设施数量大于2")
                }
                const facilitiesBackgroundParagraphStrList: string[] = splitDeviceParagraph(deviceParagraphGroup.facilitiesBackgroundParagraphPlainText);
                facilitiesBackgroundParagraphStrList.forEach((sliceStr, index) => {
                    switch (sliceStr) {
                        case '[*]':
                        case '$[*]':
                        case '$[*]':
                        case '[NAME]':
                        case '$[NAME]':
                            const replacedText = getSlateEditorInputShowText(sliceStr, docInstance, currentDeviceTopic);
                            deviceParagraphPlainText += replacedText;
                            break;
                        case '$[S]':
                        case '$[X]':
                        case '$[N]':
                        case '$[U]':
                            const entityText = getSlateEditorInputShowText(sliceStr, docInstance, currentDeviceTopic);
                            const serializatedDeviceAttr = serializationDeviceAttr(sliceStr, `DEVICE${currentDeviceTopic.id}`);
                            if (textTopic.topicName == '防火监测预警') {
                                console.log("serializatedDeviceAttr--->", serializatedDeviceAttr, entityText)
                            }
                            deviceParagraphPlainText += serializatedDeviceAttr;
                            deviceParagraphDocItemData[`${serializatedDeviceAttr}`] = entityText;
                            break;
                        default:
                            deviceParagraphPlainText += sliceStr;
                            break;
                    }
                })
            } else if (deviceParagraphGroup.deviceGroupType == 'X') {
                //处理设备节点
                //例：规划在主要景点设施和游客人群聚集处新建
                //有一些文本还是需要考虑有没有：保护地名称、保护地类型、年份、省份等等需要替换的常规文本
                const deviceBackgroundParagraphReplacedText = getReplacedDocInfoPlainText(deviceParagraphGroup.deviceBackgroundParagraphPlainText, docInstance);
                deviceParagraphPlainText += deviceBackgroundParagraphReplacedText;
                //实际上设备节点的文本不带$X、$U等等属性，所以接下来需要循环deviceTopicList自己组装
                deviceParagraphGroup.deviceTopicList.forEach((deviceTopic, deviceTopicIndex) => {
                    const currentTopic = deviceTopic;
                    const currentDeviceConstituteParagraphSlice = splitDeviceParagraph(deviceTopic.deviceBackgroundParagraph3);
                    const isLastConstituteParagraphSliceInfo: boolean = deviceTopicIndex === deviceParagraphGroup.deviceTopicList.length - 1;
                    // console.log("currentDeviceConstituteParagraphSlice--->", currentDeviceConstituteParagraphSlice)
                    currentDeviceConstituteParagraphSlice.forEach((sliceStr, sliceStrIndex) => {
                        switch (sliceStr) {
                            case '[*]':
                            case '$[*]':
                            case '$[*]':
                            case '[NAME]':
                            case '$[NAME]':
                                const replacedText = getSlateEditorInputShowText(sliceStr, docInstance, currentTopic);
                                deviceParagraphPlainText += replacedText;
                                break;
                            // case '[S]':
                            case '$[S]':
                            case '$[X]':
                            case '$[N]':
                            case '$[U]':
                                const entityText = getSlateEditorInputShowText(sliceStr, docInstance, currentTopic);
                                const serializatedDeviceAttr = serializationDeviceAttr(sliceStr, `DEVICE${deviceTopic.id}`);
                                deviceParagraphPlainText += serializatedDeviceAttr;
                                deviceParagraphDocItemData[`${serializatedDeviceAttr}`] = entityText;
                                if (sliceStr === '$[U]') {
                                    if (isLastConstituteParagraphSliceInfo) {
                                        deviceParagraphPlainText += '。';
                                    } else {
                                        deviceParagraphPlainText += '、';
                                    }
                                }
                                break;
                            default:
                                deviceParagraphPlainText += sliceStr;
                                break;
                        }
                    })
                })
            }
        })
        if (deviceParagraphPlainText) {
            paragraphDocItem.id = textTopic.id + '-cp';
            paragraphDocItem.text = deviceParagraphPlainText;
        }
        paragraphDocItem.data = deviceParagraphDocItemData;
        // if (Object.keys(deviceParagraphDocItemData).length == 0 && checkedPureDeviceTopicList.length > 0) {
        //     toastShort('warning', '有段落异常，请尽快联系管理员反馈！' + textTopic.id)
        // }
        // if (
        //     // textTopic.topicName == '防火监测预警'
        //     // ||
        //      (Object.keys(deviceParagraphDocItemData).length == 0 && checkedPureDeviceTopicList.length > 0)
        // ) {
        //     console.log("textTopic---->", textTopic)
        //     console.log("paragraphDocItem--->", paragraphDocItem)
        //     console.log("deviceParagraphDocItemData--->", deviceParagraphDocItemData)
        //     console.log("checkedPureDeviceTopicList--->", checkedPureDeviceTopicList)
        // }
        return paragraphDocItem;
    } catch (e) {
        console.error("组装设施设备段落文本失败--->err", e)
        toastShort("error", "组装设施设备段落文本失败" + e);
    }
}

const checkDocInstanceAssemblyStatus = (docInstance: DocInstance): DocInstanceAssemblyStatus => {
    try {
        const { topicList } = docInstance;
        let docInstanceAssemblyStatus: DocInstanceAssemblyStatus = 'Uninitialized';
        for (let i = 0; i < topicList.length; i++) {
            if (topicList[i].topicSlateDocItemList && topicList[i].topicSlateDocItemList.length) {
                docInstanceAssemblyStatus = 'Initialized';
                break;
            }
        }
        return docInstanceAssemblyStatus;
    } catch (e) {
        return 'Uninitialized';
    }
}


// /**
//  * 合并或者解除合并（文本节点下有且仅有一个项目节点）
//  * 1、对于侧栏 直接合并成设施设备
//  * 2、对于表格 直接合并成设施设备
//  * 3、对于文本 保留文本与设施设备属性
//  * @param tempTopicTreeData 
//  */
// const mergeOrdissolveSingleChildDeviceTopic = (
//     tempTopicTreeData: TopicType[]
// ): TopicType[] => {
//     console.log("mergeOrdissolveSingleChildDeviceTopic--->")
//     let needToReplaceTopicList: TopicType[] = [];
//     let needToDeleteTopicIdList: string[] = [];
//     dfsRecursive(tempTopicTreeData, (topic: TopicType, level: number) => {
//         if (topic.topicType == 'text') {
//             if (
//                 topic.children && topic.children.length == 1 &&
//                 topic.children[0].topicName == topic.topicName &&
//                 topic.children[0].topicType == 'device'
//             ) {
//                 const originTextTopic: TopicType = deepCloneV2(topic);
//                 const originDeviceTopic: TopicType = deepCloneV2(topic.children[0]);
//                 let newTextTopic: TopicType = deepCloneV2(topic.children[0]);
//                 newTextTopic.id = originTextTopic.id;
//                 newTextTopic.pid = originTextTopic.pid;
//                 newTextTopic.topicType = 'device';
//                 newTextTopic.isUnionTopic = true;
//                 newTextTopic.unionTextTopic = originTextTopic;
//                 newTextTopic.unionDeviceTopic = originDeviceTopic;
//                 newTextTopic.topicLevel = originTextTopic.topicLevel;
//                 newTextTopic.serialNumber = originTextTopic.serialNumber;
//                 needToReplaceTopicList.push(newTextTopic);
//             }
//         }
//     })
//     let tempTopicList: TopicType[] = tree2List(tempTopicTreeData);
//     // tempTopicList = tempTopicList.filter(item => {
//     //     return !needToDeleteTopicIdList.includes(item.id);
//     // })
//     tempTopicList = tempTopicList.map(item => {
//         let findIndex = -1;
//         for (let i = 0; i < needToReplaceTopicList.length; i++) {
//             if (needToReplaceTopicList[i].id == item.id) {
//                 findIndex = i;
//                 break;
//             }
//         }
//         if (findIndex > -1) {
//             return needToReplaceTopicList[findIndex];
//         } else {
//             return item;
//         }
//     })
//     const _tempTopicTreeData = deepCloneV2(generateTreeData(tempTopicList));
//     return _tempTopicTreeData;
// }

/**
 * 在更新前统一检查和处理一遍DocInstance
 * 1、同名大纲/项目单节点合并问题
 * 2、
 * 3、
 * @param docInstance 
 */
const processDocInstanceBeforeUpdate = (docInstance: DocInstance): DocInstance => {
    try {
        let tempDocInstance: DocInstance = deepCloneV2(docInstance);
        let { topicList } = tempDocInstance;
        let tempTopicTreeData: TopicType[] = [...generateTreeData(addTreePropertyForList(topicList))];
        tempTopicTreeData = initOrUpdateTopicTreeDataSerialNumber(tempTopicTreeData);
        // tempTopicTreeData = mergeOrdissolveSingleChildDeviceTopic(tempTopicTreeData);
        const newTopicList: TopicType[] = tree2List(tempTopicTreeData);
        tempDocInstance.topicList = deepCloneV2(newTopicList);
        return tempDocInstance;
    } catch (e) {
        toastShort("error", "processDocInstanceBeforeUpdate" + e);
    }
}

/**
 * 
 * @param textStyleMap 
 * @returns 
 */
const sortTextStyleMapAndFindMaxIndex = (textStyleMap) => {
    const indices = Object.keys(textStyleMap).map(key => parseInt(key.match(/\d+/)[0], 10));
    indices.sort((a, b) => a - b);
    const sortedTextStyleMap = {};
    indices.forEach(index => {
        const key = `$$[${index}]`;
        sortedTextStyleMap[key] = textStyleMap[key];
    });
    const maxIndex = indices.length > 0 ? indices[indices.length - 1] : 0;
    return maxIndex;
}

const generateStyledTextWithStyleOverlay = (docItem: DocItem) => {
    const { text } = docItem;
    let textStyleMap = {};
    let styledText = '';
    let maxIndex = sortTextStyleMapAndFindMaxIndex(textStyleMap);
    const regex = /([A-Za-z0-9\[\]{};:'",<.>\/?\\|\-=`~!@#$%^&*()_+]+)|([\u4e00-\u9fa5，。？！；：‘’“”（）【】《》、]+)/g;
    let match;
    while ((match = regex.exec(text)) !== null) {
        if (match[1]) {
            const styleKey = `$$[${++maxIndex}]`;
            textStyleMap[styleKey] = {
                text: match[1],
                fontFamily: 'Times New Roman'
            };
            styledText += styleKey;
        } else if (match[2]) {
            styledText += match[2];
        }
    }
    docItem.textStyleMap = textStyleMap;
    docItem.text = styledText;
    return docItem;
}


/**
 * 
 * @param topic 
 * @param docInstance 
 * @returns 
 */
const getTopicInitialSlateDocItemList = (
    topic: TopicType,
    docInstance: DocInstance,
    docConfig: DocConfig
): DocItem[] => {
    if (topic.topicName == "前言") {
        console.log("sss--->", topic, deepCloneV2(topic))
    }
    let slateDocItemList: DocItem[] = [];
    //常规的文本+项目子节点
    if (topic.topicType == 'text') {
        //第一步：生成大纲标题
        const topicTitleDocItem = assemblyTextTopicTitleParagraph(topic);
        slateDocItemList.push(topicTitleDocItem);
        //第二步：生成正文（如果需要）
        const {
            newTextTopic,
            backgroundParagraphDocItem
        } = assemblyTextTopicBackgroundParagraph(topic, docInstance);
        docInstance.topicList.forEach(node => {
            if (node.topicName == "前言") {
                console.log("sss--->111", node, deepCloneV2(node))
            }
        })
        slateDocItemList.push(backgroundParagraphDocItem);
        //第三步：生成项目联合段落
        const topicDeviceParagraphDocItem = assemblyPureDeviceChildTopicParagraph(topic, docInstance);
        slateDocItemList.push(topicDeviceParagraphDocItem);
        //预设的文本段落，比如规划创建之时，填写的基本信息，以及附表内容，所以也只在初始化的时候加入进去。
        const presetDocItemList = presetDocItemText(topic, docInstance, docConfig);
        slateDocItemList = slateDocItemList.concat(presetDocItemList);
    }
    slateDocItemList = slateDocItemList.filter(paragraph => paragraph.id);
    return slateDocItemList;
}

/**
 * 
 * @param docItemId1 
 * @param docItemId2 
 * @returns 
 */
const checkTwoDocItemIdIsEqual = (docItemId1: any, docItemId2: any) => {
    try {
        docItemId1 = docItemId1 + '';
        docItemId2 = docItemId2 + '';
        if (docItemId1.split('-').length == 1) {
            return docItemId1 === docItemId2
        }
        if (
            docItemId1.split('-')[0] === docItemId2.split('-')[0] &&
            docItemId1.split('-')[1] === docItemId2.split('-')[1]
        ) {
            return true;
        }
        return false;
    } catch (e) {
        return false;
    }
}

/**
 * 混合段落
 * @param topic 
 * @param docInstance 
 * @returns 
 */
const mergeTopicSlateParagraph = (
    topic: TopicType,
    docInstance: DocInstance,
    docConfig: DocConfig,
    tempTopicTreeData: TopicType[],
    originTableData: TableDataCell[],
    gridTableData: TableDataCell[][]
): {
    mergedSlateDocItemList: DocItem[],
    slateDocItemListChanged: boolean
} => {
    try {
        let slateDocItemListChanged = false;
        let slateDocItemList: DocItem[] = topic.topicSlateDocItemList || [];
        let needToReplaceDocItemList: DocItem[] = [];
        //新的系统章节
        if (isSystemChapterTopicName(topic)) {
            const {
                topicSystemDocItemList,
                hasChangedSystemChapter
            } = initOrUpdateSystemChapter(
                deepCloneV2(topic),
                deepCloneV2(docInstance),
                docConfig,
                deepCloneV2(tempTopicTreeData),
                originTableData,
                gridTableData
            );
            // const oldSystemChapterDocItemList = slateDocItemList.filter(docItem => String(docItem.id).includes('-SP-'))
            if (hasChangedSystemChapter) {
                slateDocItemListChanged = true;
                //TODO 现在是粗暴替换和插入
                let topicSlateDocItemList1 = slateDocItemList.filter(ele => !String(ele.id).includes('-SP-'));
                let topicSlateDocItemList2 = deepCloneV2(topicSlateDocItemList1.concat(topicSystemDocItemList));
                slateDocItemList = deepCloneV2(topicSlateDocItemList2);
            }
        }
        if (isPresetresetDocItemTextTopicName(topic)) {
            // console.log("这是isPresetresetDocItemTextTopicName--->", slateDocItemList)
        } else if (slateDocItemList && slateDocItemList.length) {
            const topicFreshSlateParagraph: DocItem[] = getTopicInitialSlateDocItemList(topic, docInstance, docConfig);
            topicFreshSlateParagraph.forEach((docItem, index) => {

                let findExistSlateParagraph = slateDocItemList.find(item => checkTwoDocItemIdIsEqual(item.id, docItem.id))
                if (findExistSlateParagraph) {
                    if (
                        (findExistSlateParagraph.type == DocItemType.P ||
                            findExistSlateParagraph.type == DocItemType.CP) &&
                        findExistSlateParagraph.externalData &&
                        findExistSlateParagraph.externalData.childTopicIdSortList &&
                        findExistSlateParagraph.externalData.childTopicIdSortList.length
                    ) {
                        //这是设备段落
                        if (docItem.externalData.childTopicIdSortList.toString() !== findExistSlateParagraph.externalData.childTopicIdSortList.toString()) {
                            // console.log("这是需要替换的docItem---->", docItem);
                            needToReplaceDocItemList.push(docItem);
                        } else {
                            if (docItem.id == "660a5a0557a0600ec2370a08-p") {
                                console.log("瞭望塔---->", deepCloneV2(docItem.data))
                            }
                            findExistSlateParagraph.data = deepCloneV2(docItem.data);
                        }
                    } else {
                        if (docItem.data) {
                            findExistSlateParagraph.data = deepCloneV2(docItem.data);
                        }
                    }
                } else {
                    slateDocItemListChanged = true;
                    slateDocItemList.push(docItem);
                }
            })
            if (needToReplaceDocItemList.length) {
                slateDocItemListChanged = true;
                slateDocItemList = slateDocItemList.map(docItem => {
                    let findDocItem = needToReplaceDocItemList.find(ele => ele.id == docItem.id);
                    if (findDocItem) {
                        return findDocItem;
                    }
                    return docItem;
                })
            }
        }
        return {
            mergedSlateDocItemList: deepCloneV2(slateDocItemList),
            slateDocItemListChanged,
        };
    } catch (e) {
        toastShort('error', '补全docItemData异常-->' + e)
    }
}


/**
 * 提取input对应的信息
 * @param inputData 
 * @returns 
 */
const getSlateEditorInputInfoByInputData = (
    inputData: Record<string, any>
): SlateEditorInputInfo => {
    try {
        console.log("inputData--->", inputData)
        const inputDataIdStrList = Object.keys(inputData)[0].split('/');
        const inputValue = Object.values(inputData)[0];
        const docItemId = inputDataIdStrList[0];
        let textTopicId = inputDataIdStrList[0].split('-')[0];
        const inputMarkerStrList = inputDataIdStrList[1].split('DEVICE');
        let deviceTopicId = inputMarkerStrList[1].replace(']', '');
        //docItem中为了区别使用的标记
        const docItemInputMarker = inputDataIdStrList[1];
        //实际的 inputmarker，也就是$[U]等等
        let realInputMarker = inputDataIdStrList[1].replace(deviceTopicId, '').replace('DEVICE', '');
        let inputInfo: SlateEditorInputInfo = {
            docItemId: docItemId,
            textTopicId: textTopicId,
            deviceTopicId: deviceTopicId,
            docItemInputMarker: docItemInputMarker,
            realInputMarker: realInputMarker,
            inputValue: inputValue,
        }
        return inputInfo;
    } catch (e) {
        toastShort('error', '提取input对应的信息' + e)
    }
}

/**
 * 删除节点的同时，把此节点下所有数据挪到其上级节点去
 * @param topicList 
 * @param targetTopicId 
 * @returns 
 */
const deleteTextTopicAndMoveChildTopicList = (
    topicList: TopicType[],
    targetTopicId: string,
): {
    newTopicList: TopicType[]
} => {
    let findTextTopicIndex = -1;
    let oldPid = "";
    let newPid = "";
    let flag = false;
    let newTopicList: TopicType[] = [];
    //删除目标节点
    for (let i = 0; i < topicList.length; i++) {
        if (topicList[i].id == targetTopicId) {
            const textTopic = topicList[i];
            findTextTopicIndex = i;
            oldPid = textTopic.id;
            newPid = textTopic.pid;
            if (textTopic.children) {
                textTopic.children.forEach(ele => {
                    if (ele.topicType == 'text') {
                        flag = true;
                    }
                })
            }
            break;
        }
    }
    topicList.splice(findTextTopicIndex, 1);
    if (flag) {
        const moveIndexs = [];
        //下级节点提升层级到删除节点层级
        newTopicList = topicList.map((topic, index) => {
            if (topic.pid == oldPid) {
                let tempTextTopic = deepCloneV2(topic);
                tempTextTopic.pid = newPid;
                moveIndexs.push(index)
                return tempTextTopic;
            } else {
                return topic;
            }
        })
        const startIdxs = moveIndexs.sort((a, b) => a - b);
        const elementsToMove = [];
        for (let i = startIdxs.length - 1; i >= 0; i--) {
            const idx = startIdxs[i];
            elementsToMove.unshift(newTopicList.splice(idx, 1)[0]);
        }
        newTopicList.splice(findTextTopicIndex, 0, ...elementsToMove);
    } else {
        //下级节点并入删除节点父节点
        newTopicList = topicList.map(topic => {
            if (topic.id == newPid) {
                let tempTextTopic = deepCloneV2(topic);
                topic = { ...tempTextTopic };
            }
            if (topic.pid == oldPid) {
                topic.pid = newPid;
            }
            return topic;
        })
    }
    return {
        newTopicList,
    };
}

const deleteDeviceTopicAndResetFormat = (
    topicList: TopicType[],
    targetTopicId: string,
) => {
    topicList.splice(topicList.findIndex(topic => topic.id == targetTopicId && topic.topicType == 'device'), 1);
    let newTopicList: TopicType[] = deepCloneV2(topicList);
    return {
        newTopicList,
    };
}

/**
 * 
 * @param topic 
 * @param newTopicSystemChapterDocItemList 
 * @returns 
 */
const mergeTopicSystemChapter = (
    originDocItemList: DocItem[],
    newTopicSystemChapterDocItemList: DocItem[],
    docInstanceAssemblyStatus: DocInstanceAssemblyStatus
): DocItem[] => {
    try {
        console.log("originDocItemList--->", originDocItemList)
        console.log("newTopicSystemChapterDocItemList--->", newTopicSystemChapterDocItemList)
        // let _originDocItemList: DocItem[] = docInstanceAssemblyStatus == 'Uninitialized' ? [originDocItemList[0]] : [...originDocItemList];
        // let _originDocItemList: DocItem[] = [...originDocItemList];
        originDocItemList.forEach(item => {
            let findNewSyetemChapterDocItem = newTopicSystemChapterDocItemList.find(ele => {
                return ele.id == item.id;
            })
            item = deepCloneV2(findNewSyetemChapterDocItem);
        })
        let needToAdditionalSyetemChapterDocItemList = newTopicSystemChapterDocItemList.filter(item => {
            return !originDocItemList.find(ele => {
                return ele.id == item.id;
            })
        })
        if (needToAdditionalSyetemChapterDocItemList) {
            originDocItemList = originDocItemList.concat(needToAdditionalSyetemChapterDocItemList);
        }
        console.log("originDocItemList--->合并后---->", deepCloneV2(originDocItemList))
        return originDocItemList;
    } catch (e) {
        return originDocItemList || [];
    }
}

/**
 * 构造投资估算表数据
 */
const getGridTableDataCell = (
    docInstance: DocInstance,
    docConfig: DocConfig,
): {
    originTableData: TableDataCell[],
    gridTableData: TableDataCell[][]
} => {
    const {
        newTableData
    } = initExcelBuninessContentForWorker(
        docInstance,
        docConfig,
        [...initMergeCellBoundGroup],
        [...initTableHeader]
    );
    const gridTableData = convertNewTableDataToGridTableData(newTableData);
    return {
        originTableData: newTableData,
        gridTableData: gridTableData
    }
};

const isSystemChapterTopicName = (topic: TopicType): boolean => {
    const systemChapterTopicNameList = [
        {
            topicName: "重点工程",
            topicLevelList: [0, 1, 2, 3, 4, 5],
        },
        {
            topicName: "规划期限",
            topicLevelList: [0, 1, 2, 3, 4, 5],
        },
        {
            topicName: "规划主要建设内容",
            topicLevelList: [0, 1, 2, 3],
        },
        {
            topicName: "投资计划安排",
            topicLevelList: [0, 1, 2, 3],
        },
        {
            topicName: "规划投资",
            topicLevelList: [0, 1, 2, 3],
        },
        {
            topicName: "存在问题与对策",
            topicLevelList: [0, 1, 2, 3],
        },
        {
            topicName: "总体目标",
            topicLevelList: [0, 1, 2, 3],
        },
        {
            topicName: "近期目标",
            topicLevelList: [0, 1, 2, 3],
        },
        {
            topicName: "远期目标",
            topicLevelList: [0, 1, 2, 3],
        },
        {
            topicName: "中长期目标",
            topicLevelList: [0, 1, 2, 3],
        },
    ]
    return topic.topicType == 'text' && systemChapterTopicNameList.findIndex(ele => ele.topicName == topic.topicName) > -1;
}

/**
 * docInstance转换成Slate段落数据
 * @param docInstance 
 * @param docConfig 
 */
const translateDocInstanceToSlateEditorData = (
    docInstance: DocInstance,
    docConfig: DocConfig,
): {
    docItemList: DocItem[],
    docInstance: DocInstance,
} => {
    try {
        // const tempDocInstance: DocInstance = { ...docInstance };
        const tempDocInstance: DocInstance = deepCloneV2(docInstance);
        const {
            originTableData,
            gridTableData
        } = getGridTableDataCell(docInstance, docConfig)
        let allAdditionalDocItemList = [];
        const { topicList, additionalDocItemList = [] } = tempDocInstance;
        allAdditionalDocItemList = allAdditionalDocItemList.concat(additionalDocItemList);
        //slate编辑器数据
        let slateDocItemList: DocItem[] = [];
        //topic树状数据
        let _tempTopicTreeData: TopicType[] = [...generateTreeData(addTreePropertyForList(topicList))];
        console.log("_tempTopicTreeData--->111", deepCloneV2(_tempTopicTreeData))
        let tempTopicTreeData = initOrUpdateTopicTreeDataSerialNumber(_tempTopicTreeData);
        const docInstanceAssemblyStatus = checkDocInstanceAssemblyStatus(docInstance);
        console.log("docInstanceAssemblyStatus---->", docInstanceAssemblyStatus)
        if (docInstanceAssemblyStatus == 'Initialized') {
            dfsRecursive(tempTopicTreeData, (topic: TopicType, level: number) => {
                const topicCheckedStatus: TopicCheckedStatus = getTopicNodeChckedStatus(topic);
                if (topic.topicType == 'text' && ['halfChecked', 'fullChecked'].includes(topicCheckedStatus)) {
                    //收集每个 topic下面的段落：标题、正文、表格、表头等等
                    let topicSlateDocItemList: DocItem[] = [];
                    if (!topic.topicSlateDocItemList || topic.topicSlateDocItemList.length == 0) {
                        topicSlateDocItemList = getTopicInitialSlateDocItemList(topic, docInstance, docConfig);
                    } else {
                        const {
                            mergedSlateDocItemList,
                            slateDocItemListChanged,
                        } = mergeTopicSlateParagraph(topic, docInstance, docConfig, tempTopicTreeData, originTableData, gridTableData);
                        if (slateDocItemListChanged) {
                            topicSlateDocItemList = deepCloneV2(mergedSlateDocItemList);
                        } else {
                            topicSlateDocItemList = topic.topicSlateDocItemList;
                        }
                    }
                    slateDocItemList = slateDocItemList.concat(topicSlateDocItemList);
                }
            })
        } else if (docInstanceAssemblyStatus == 'Uninitialized') {
            dfsRecursive(tempTopicTreeData, (topic: TopicType, level: number) => {
                const topicCheckedStatus: TopicCheckedStatus = getTopicNodeChckedStatus(topic);
                if (['halfChecked', 'fullChecked'].includes(topicCheckedStatus)) {
                    //1、收集每个 topic下面的段落：标题、正文、表格、表头等等
                    let topicSlateDocItemList: DocItem[] = getTopicInitialSlateDocItemList(topic, docInstance, docConfig);
                    //2、检查是否需要生成系统章节
                    const {
                        topicSystemDocItemList,
                        hasChangedSystemChapter
                    } = initOrUpdateSystemChapter(
                        topic,
                        docInstance,
                        docConfig,
                        tempTopicTreeData,
                        originTableData,
                        gridTableData
                    );
                    if (hasChangedSystemChapter) {
                        // topicSlateDocItemList = mergeTopicSystemChapter(topicSlateDocItemList, topicSystemDocItemList, docInstanceAssemblyStatus);
                        topicSlateDocItemList = deepCloneV2(topicSlateDocItemList.concat(topicSystemDocItemList));
                    }
                    if (topicSlateDocItemList && topicSlateDocItemList.length) {
                        slateDocItemList = slateDocItemList.concat(topicSlateDocItemList);
                    }
                    topic.topicSlateDocItemList = [...topicSlateDocItemList];
                }
            })
            const scheduleTableAdditionalDocItemList = generateScheduleTableAdditionalDocItemList(docInstance, docConfig);
            if (scheduleTableAdditionalDocItemList && scheduleTableAdditionalDocItemList.length) {
                allAdditionalDocItemList = allAdditionalDocItemList.concat(scheduleTableAdditionalDocItemList);
            }
        }
        if (allAdditionalDocItemList && allAdditionalDocItemList.length) {
            slateDocItemList = slateDocItemList.concat([...allAdditionalDocItemList.filter(ele => ele && ele.id)])
        }
        return {
            docItemList: slateDocItemList,
            docInstance: tempDocInstance,
        };
    } catch (e) {
        console.error("err---->", e)
        return {
            docInstance: docInstance,
            docItemList: [],
        };
    }
}

/**
 * 手动更新docItemList
 * @param docItemList 
 * @param changedDocItemList 
 * @returns 
 */
const manualUpdateDocItemList = (
    docItemList: DocItem[],
    changedDocItemList: DocItemChangeRecord[]
): DocItem[] => {
    let tempDocItemList: DocItem[] = deepCloneV2(docItemList);
    changedDocItemList.forEach(changeRecord => {
        if (changeRecord.changeType === 'removed') {
            for (let i = 0; i < tempDocItemList.length; i++) {
                if (tempDocItemList[i].id == changeRecord.docItemId) {
                    tempDocItemList.splice(i, 1);
                    break;
                }
            }
        }
    })
    return tempDocItemList;
}

/**
 * Slate段落数据转换成docInstance
 * @param docInstance 
 * @param slateEditorData 
 * @returns 
 */
const translateSlateEditorDataToDocInstance = (
    docInstance: DocInstance,
    slateEditorData: DocItem[],
    oldSlateEditorData: DocItem[],
    inpuData?: Record<string, any>
): {
    newDocInstance: DocInstance,
    needForceUpdate: boolean,
    newDocItemList: DocItem[]
} => {
    try {
        let newDocInstance: DocInstance = null;
        newDocInstance = docInstance;
        // return {
        //     needForceUpdate: false,
        //     newDocInstance,
        //     newDocItemList: slateEditorData
        // }
        let needForceUpdate = false;
        let newDocItemList: DocItem[] = deepCloneV2(slateEditorData);
        console.log("newDocItemList--->", newDocItemList)
        if (inpuData) {
            newDocInstance = mergeNewInputDataToDocInstance(inpuData, docInstance);
        } else {
            newDocInstance = deepCloneV2(docInstance)
        }
        const changedSlateEditorDocItemList: DocItemChangeRecord[] = getChangedSlateEditorDocItemList(slateEditorData, oldSlateEditorData);
        // console.log("changedSlateEditorDocItemList--->", changedSlateEditorDocItemList)
        newDocItemList = manualUpdateDocItemList(newDocItemList, changedSlateEditorDocItemList);
        const newAdditionalDocItemList = newDocItemList.filter(item => String(item.id).includes('ADDITIONAL'))
        let { topicList } = newDocInstance;
        //先处理：
        //1、标题删除 -> 删除对应 textTopic 以及合并下级所有节点到其父节点
        //2、设备input删除 -> 如果删除的input包含设备名称，那么就删除掉这个设备。
        changedSlateEditorDocItemList.forEach((changeRecord, index) => {
            if (
                checkDocItemIsTitleParagraph(changeRecord.docItemType) &&
                changeRecord.changeType == 'removed'
            ) {
                // console.log("removed--changeRecord---->", changeRecord)
                needForceUpdate = true;
                const {
                    newTopicList,
                } = deleteTextTopicAndMoveChildTopicList(
                    topicList,
                    changeRecord.docItemTextTopicId
                );
                topicList = newTopicList;
            } else if (changeRecord.changeType == 'changed') {
                // console.log("这是changeRecord---->", changeRecord)
                // if (changeRecord.deletedMarkList && changeRecord.deletedMarkList.length) {
                //     // console.log("这是deletedMarkList---->", changeRecord)
                //     //如果说删除了名称，那么就要删除整个项目节点
                //     if (changeRecord.deletedMarkList.find(ele => ele.includes("$[S") || ele.includes("$[X"))) {
                //         needForceUpdate = true;
                //         const deviceTopicId = changeRecord.deletedMarkList[0].substring(9, changeRecord.deletedMarkList[0].length - 1);
                //         const {
                //             newTopicList,
                //         } = deleteDeviceTopicAndResetFormat(
                //             topicList,
                //             deviceTopicId
                //         );
                //         topicList = newTopicList;
                //         const findDocItem = newDocItemList.find(docItem => docItem.id == changeRecord.newDocItem.id);
                //         let replacedDocItemText = '';
                //         const dynamicTextReg = /(\$?\[[SXNU].*?])|(\$?\[\*])|(\$?\[NAME])|(\$?\[P])|(\$?\[type])|(\$\$\[\d+])/;
                //         let needToReplacedMarkList = [];
                //         ["X", "S", "U", "N"].forEach(mark => {
                //             const searchStr = `$[${mark}DEVICE${deviceTopicId}]`;
                //             needToReplacedMarkList.push(searchStr);
                //         })
                //         findDocItem.text.split(dynamicTextReg)
                //             .filter(Boolean)
                //             .forEach(str => {
                //                 if (dynamicTextReg.test(str) && needToReplacedMarkList.includes(str)) {
                //                 } else {
                //                     replacedDocItemText += str
                //                 }
                //             })
                //         findDocItem.text = replacedDocItemText;
                //     }
                // }
            }
        })
        topicList.forEach(topic => {
            const currentTopicCheckedStatus = getTopicNodeChckedStatus(topic);
            if (currentTopicCheckedStatus !== 'noChecked') {
                if (topic.topicType == 'text') {
                    //找到当前文本节点关联的段落（如果有）
                    let currentTextTopicSlateParagraphList: DocItem[] = slateEditorData.filter(item => {
                        return item.id.toString().includes(topic.id);
                    });
                    topic.topicSlateDocItemList = currentTextTopicSlateParagraphList;
                    //处理标题
                    if (
                        topic.topicSlateDocItemList &&
                        topic.topicSlateDocItemList.length
                    ) {
                        let textTopicTitleDocItem = topic.topicSlateDocItemList[0];
                        if (
                            textTopicTitleDocItem &&
                            ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(textTopicTitleDocItem.type) &&
                            textTopicTitleDocItem.data &&
                            textTopicTitleDocItem.data['$[INDEX]']
                        ) {
                            //@ts-ignore
                            topic.topicName = textTopicTitleDocItem.plainText.replace(textTopicTitleDocItem.data['$[INDEX]'], '').trim();
                        }
                    }
                }
            }
        })
        topicList.forEach(topic => {
            delete topic.children;
        })
        newDocInstance.topicList = deepCloneV2(topicList);
        newDocInstance.additionalDocItemList = newAdditionalDocItemList;
        return {
            newDocInstance,
            needForceUpdate,
            newDocItemList,
        };
    } catch (e) {
        toastShort("error", "translateSlateEditorDataToDocInstance" + e)
        console.error("translateSlateEditorDataToDocInstance-->err", e)
        return {
            newDocInstance: docInstance,
            needForceUpdate: false,
            newDocItemList: slateEditorData
        };
    }
}

/**
 * 首次进入编制页面，组装规划数据、规划配置
 * @param docInstance 
 * @param docConfig 
 * @param planBasisList 
 * @returns 
 */
const generateDocInstance = (
    docInstance: DocInstance,
    docConfig: DocConfig,
    planBasisList: PlanningBasisType[]
): {
    generatedDocConfig: DocConfig,
    generatedDocInstance: DocInstance
} => {
    try {
        let tempDocInstance = processDocInstanceBeforeUpdate(docInstance);
        let tempDocConfig = docConfig;
        let tempTopicList = tempDocInstance.topicList;
        const docInstanceAssemblyStatus = checkDocInstanceAssemblyStatus(tempDocInstance);
        if (docInstanceAssemblyStatus == 'Uninitialized') {
            tempDocInstance = checkTopicNodeBeforeInitalization(tempDocInstance);
        }
        const {
            docBaseConfigInfo: {
                docMoneyCardinalNumber = 1
            }
        } = docConfig;
        tempTopicList.forEach(topic => {

            if (topic.topicType == 'device') {
                if (topic.unitPrice) {
                    topic._unitPrice = parsePrice(Number(topic.unitPrice) * docMoneyCardinalNumber).toString();
                }
                if (topic._unitPrice) {
                    //@ts-ignore
                    topic.investmentCompositionMoney = parsePrice(topic._unitPrice * topic.count)
                }
            } else {
                if (isSystemChapterTopicName(topic)) {
                    topic.backgroundParagraph1 = '';
                    topic.backgroundParagraph2 = '';
                    topic.backgroundParagraph3 = '';
                    topic.backgroundParagraph4 = '';
                }
                topic.nearFutureMoneyRateOfValue = '';
                topic.mediumAndLongTermMoneyRateOfValue = '';
            }
            tempTopicList.forEach(topic => {
                if (topic.topicSlateDocItemList && topic.topicSlateDocItemList.length) {
                    try {
                        if (typeof topic.topicSlateDocItemList == 'string') {
                            //@ts-ignore
                            topic.topicSlateDocItemList = JSON.parse(topic.topicSlateDocItemList);
                        }
                    } catch (e) {
                        console.error("构建docInstance时，topicSlateParagraphList解析失败:::" + topic.topicName, e);
                    }
                }
            })
            if (isEmpty(topic.defaultChecked)) {
                topic.defaultChecked = topic.checked;
            }
        })
        let tempTopicTreeData = generateTreeData(addTreePropertyForList(tempTopicList));
        tempTopicTreeData = updateTopicRealCheckedStatus(tempTopicTreeData);
        // tempDocInstance.topicList = tempTopicList;
        tempDocInstance.topicList = tree2List(tempTopicTreeData);
        tempDocConfig.planBasisList = planBasisList;
        tempDocInstance = processDocInstanceBeforeUpdate(tempDocInstance);
        if (isEmpty(tempDocConfig.docBaseConfigInfo)) {
            tempDocConfig = defaultDocConfig;
        }
        if (isEmpty(tempDocConfig.docExtraConfigInfo)) {
            tempDocConfig.docExtraConfigInfo = defaultDocExtraConfigInfo;
        } else {
            const mergedDocExtraConfigInfo = {
                ...defaultDocExtraConfigInfo,
                ...tempDocConfig.docExtraConfigInfo
            }
            if (
                Number(mergedDocExtraConfigInfo.zoom) < 0.1 ||
                Number(mergedDocExtraConfigInfo.zoom) > 4
            ) {
                toastShort('warning', '表格缩放比例异常，已为您恢复至默认比例')
                mergedDocExtraConfigInfo.zoom = 1;
            }
            tempDocConfig.docExtraConfigInfo = mergedDocExtraConfigInfo;
        }

        return {
            generatedDocConfig: deepCloneV2(tempDocConfig),
            generatedDocInstance: deepCloneV2(tempDocInstance)
        }
    } catch (e) {
        console.error("构建docInstance失败--->", e)
        toastShort("error", "generateDocInstance" + e)
        return {
            generatedDocConfig: docConfig,
            generatedDocInstance: docInstance
        }
    }
}

/**
 * 合并输入框新的数据到指定DocItem
 * 返回更新后的Slate DocItem格式数据
 * @param slateInputNewValue 
 * @param slateEditorData 
 */
const mergeNewSlateEditorInputValueToDocItemList = (
    slateInputNewValue: Record<string, string>,
    slateEditorData: DocItem[]
): DocItem[] => {
    const slateEditorInputInfo = getSlateEditorInputInfoByInputData(slateInputNewValue);
    console.log("slateEditorInputInfo--->", slateEditorInputInfo)
    const {
        textTopicId,
        deviceTopicId,
        docItemId,
        docItemInputMarker,
        realInputMarker,
        inputValue
    } = slateEditorInputInfo;
    let findDocItem = slateEditorData.find(item => {
        return item.id == docItemId;
    })
    console.log("slateEditorData--->", slateEditorData, findDocItem)
    if (findDocItem) {
        findDocItem.data[docItemInputMarker] = inputValue;
    }
    return slateEditorData;
}

/**
 * 
 * @param inputMarker '$[U]' | '$[S]' | '$[X]' | '$[N]'
 */
const getDeviceTopicAttrByInputMarker = (inputMarker: string) => {
    let deviceTopicAttr = '';
    switch (inputMarker) {
        case '[N]':
        case '$[N]':
            deviceTopicAttr = 'count';
            break;
        case '[U]':
        case '$[U]':
            deviceTopicAttr = 'unit';
            break;
        case '[S]':
        case '[X]':
        case '$[S]':
        case '$[X]':
            deviceTopicAttr = 'topicName';
            break;
        default:
            break;
    }
    return deviceTopicAttr;
}

/**
 * 把新的输入框数值合并到docInstance
 * @param inputData 
 * @param docInstance 
 */
const mergeNewInputDataToDocInstance = (
    inputData: Record<string, any>,
    docInstance: DocInstance
): DocInstance => {
    // console.log("触发---->mergeNewInputDataToDocInstance", inputData)
    let newDocInstance: DocInstance = deepCloneV2(docInstance);
    const {
        topicList
    } = newDocInstance;
    const slateEditorInputInfo = getSlateEditorInputInfoByInputData(inputData);
    // console.log("slateEditorInputInfo--->", slateEditorInputInfo)
    const {
        textTopicId,
        deviceTopicId,
        realInputMarker,
        inputValue
    } = slateEditorInputInfo;
    let changedTopicList: TopicType[] = [];
    let tempTopicTreeData: TopicType[] = [...generateTreeData(addTreePropertyForList(topicList))];
    const deviceTopicAttr = getDeviceTopicAttrByInputMarker(realInputMarker);
    dfsRecursive(tempTopicTreeData, (topic: TopicType, level: number) => {
        if (topic.topicType == 'device' && topic.id == deviceTopicId) {
            let tempDeviceTopic: TopicType = deepCloneV2(topic);
            tempDeviceTopic[deviceTopicAttr] = inputValue;
            changedTopicList.push(deepCloneV2(tempDeviceTopic));
        }
    })
    // console.log("changedTopicList--->", changedTopicList)
    let tempTopicList = [...topicList];
    changedTopicList.forEach(newTopic => {
        let findIndex = -1;
        for (let i = 0; i < tempTopicList.length; i++) {
            if (tempTopicList[i].id == newTopic.id) {
                findIndex = i;
                break;
            }
        }
        if (findIndex > -1) {
            tempTopicList[findIndex] = deepCloneV2(newTopic);
        }
    })
    newDocInstance.topicList = deepCloneV2(tempTopicList);
    return newDocInstance;
}

const checkDocItemIsTitleParagraph = (docItemType: DocItemType): boolean => {
    if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(docItemType)) {
        return true;
    }
    return false;
}

/**
 * 获取删除掉的mark
 * @param originText 
 * @param newText 
 */
const getDeletedMarkList = (originText: string, newText: string) => {
    try {
        const deletedMarkList: string[] = [];

        const dynamicTextReg = /(\$?\[[SXNU].*?])/;
        const originTextSlice: string[] = originText.split(dynamicTextReg).filter(Boolean);
        const newTextSlice: string[] = newText.split(dynamicTextReg).filter(Boolean);
        let markRecordByOriginText: { mark: string, count: number }[] = [];
        let markRecordByNewText: { mark: string, count: number }[] = [];
        originTextSlice.forEach(strSlice => {
            if (dynamicTextReg.test(strSlice)) {
                const findIndex = markRecordByOriginText.findIndex(ele => ele.mark == strSlice)
                if (findIndex > -1) {
                    markRecordByOriginText[findIndex].count++;
                } else {
                    markRecordByOriginText.push({ mark: strSlice, count: 1 })
                }
            }
        })
        newTextSlice.forEach(strSlice => {
            if (dynamicTextReg.test(strSlice)) {
                const findIndex = markRecordByNewText.findIndex(ele => ele.mark == strSlice)
                if (findIndex > -1) {
                    markRecordByNewText[findIndex].count++;
                } else {
                    markRecordByNewText.push({ mark: strSlice, count: 1 })
                }
            }
        })
        markRecordByOriginText.forEach(markRecord => {
            const findNewMarkerRecord = markRecordByNewText.find(ele => ele.mark == markRecord.mark);
            if (!findNewMarkerRecord || findNewMarkerRecord.count < markRecord.count) {
                deletedMarkList.push(markRecord.mark)
            }
        })

        if (deletedMarkList.length) {
            console.log("deletedMarkList--->", deletedMarkList)
            console.log("markRecordByNewText--->", markRecordByNewText)
            console.log("markRecordByOriginText--->", markRecordByOriginText)
        }
        return deletedMarkList.filter((item, index) => deletedMarkList.indexOf(item) === index);
    } catch (e) {
        return [];
    }
}

function generatePlainText(text, textStyleMap = {}) {
    Object.keys(textStyleMap).forEach(key => {
        const replacementText = textStyleMap[key].text;
        const regex = new RegExp(`\\$\\$\\[${key.substring(2, key.length)}\\]`);
        text = text.replace(regex, replacementText);
    });
    return text;
}

const getTitlePlainText = (docItem: DocItem): string => {
    if (docItem.type.includes('h')) {
        //@ts-ignore
        return docItem.plainText ? docItem.plainText.replace(docItem.data['$[INDEX]'], '').trim() : docItem.text;
    } else {
        return generatePlainText(docItem.text, docItem.textStyleMap);
    }

}

/**
 * 获取改变了的docItem前后对比
 * @param currentDocItemList 
 * @param oldDocItemList 
 * @returns 
 */
const getChangedSlateEditorDocItemList = (
    currentDocItemList: DocItem[],
    oldDocItemList: DocItem[],
): DocItemChangeRecord[] => {
    currentDocItemList = currentDocItemList.filter(item => {
        if (
            isEmpty(getTitlePlainText(item)) && checkDocItemIsTitleParagraph(item.type)
        ) {
            return false;
        }
        return item
    })

    let changeDocItemRecordList: DocItemChangeRecord[] = [];
    currentDocItemList = [...currentDocItemList].filter(item => {
        return !(item.id + '').includes('-ADDITIONAL') && !String(item.id).includes('-SP-')
    })
    oldDocItemList = [...oldDocItemList].filter(item => {
        return !(item.id + '').includes('-ADDITIONAL') && !String(item.id).includes('-SP-')
    })
    oldDocItemList.forEach((oldDocItem, oldDocItemIndex) => {
        const currentDocItem = currentDocItemList.find(ele => {
            return ele.id == oldDocItem.id;
        })
        if (currentDocItem) {
            const oldText = getTitlePlainText({ ...oldDocItem });
            const newText = getTitlePlainText({ ...currentDocItem });
            if (
                (oldText !== newText && !isEmpty(newText)) ||
                oldDocItem.plainText != currentDocItem.plainText ||
                // (oldDocItem.text !== currentDocItem.text && !isEmpty(currentDocItem.text)) ||
                JSON.stringify(oldDocItem.textStyleMap || {}) !== JSON.stringify(currentDocItem.textStyleMap || {})
            ) {
                // console.log("文本发生变化---->currentDocItem", currentDocItem);
                // console.log("文本发生变化---->oldDocItem", oldDocItem);
                // console.log("文本发生变化---->newText", newText);
                // console.log("文本发生变化---->oldText", oldText);
                changeDocItemRecordList.push({
                    docItemId: currentDocItem.id,
                    changeType: 'changed',
                    newDocItem: currentDocItem,
                    oldDocItem: oldDocItem,
                    docItemType: currentDocItem.type,
                    //@ts-ignore
                    docItemTextTopicId: currentDocItem.id.split('-')[0],
                    deletedMarkList: getDeletedMarkList(oldDocItem.text, currentDocItem.text),
                })
            }
        } else {
            changeDocItemRecordList.push({
                changeType: 'removed',
                //@ts-ignore
                docItemTextTopicId: oldDocItem.id.split('-')[0],
                docItemId: oldDocItem.id,
                oldDocItem: oldDocItem,
                newDocItem: null,
                docItemType: oldDocItem.type
            })
        }
    })
    // console.log("changeDocItemRecordList--->", changeDocItemRecordList)
    return changeDocItemRecordList;
}

/**
 * 
 * @param wordParagraphList 
 * @returns 
 */
const convertWordParagraphListToDocItemList = (
    wordParagraphList: WordParagraphBlock[],
): DocItem[] => {
    let docItemList: DocItem[] = [];
    wordParagraphList.forEach(wordParagraph => {
        // const docItemStyled = convertToDocItemStyleFormat(wordParagraph)
        // console.log("docItemStyled--->", docItemStyled)
        switch (wordParagraph.type) {
            case 'text':
                let tempTextDocItem: DocItem = {
                    id: wordParagraph.blockId || 'additionalDocItem-' + getUuid(8),
                    text: wordParagraph.text,
                    type: wordParagraph.paragraphStyle == 'table_name_paragraph' ? DocItemType.TABLE_NAME : DocItemType.P,
                }
                if (wordParagraph.paragraphStyle == 'table_name_paragraph') {
                    tempTextDocItem.style = {
                        align: AlignEnum.center
                    }
                } else if (wordParagraph.paragraphStyle == 'table_desc_paragraph') {
                    tempTextDocItem.style = {
                        align: AlignEnum.right
                    }
                    // tempTextDocItem.
                }
                if (wordParagraph.docItem) {
                    tempTextDocItem.text = wordParagraph.docItem.text;
                    tempTextDocItem.textStyleMap = wordParagraph.docItem.textStyleMap;
                }
                docItemList.push(tempTextDocItem);
                break;
            case 'Table':
                const tableInfo = {
                    tableData: wordParagraph.tableData,
                    tableDesc: wordParagraph.tableDesc,
                    rowSpanInfoList: wordParagraph.tableRowSpanList,
                    colSpanInfoList: wordParagraph.tableColSpanList,
                    tableHeaderEndRowIndex: wordParagraph.tableHeaderRowIndex
                };
                let tempTableDocItem: DocItem = {
                    id: wordParagraph.blockId || 'additionalDocItem-' + getUuid(8),
                    type: DocItemType.TABLE,
                    text: '表格',
                    externalData: tableInfo,
                }
                docItemList.push(tempTableDocItem);
                break;
            case 'LaTex':
                let tempLaTexDocItem: DocItem = {
                    id: wordParagraph.blockId || 'additionalDocItem-' + getUuid(8),
                    type: DocItemType.LaTex,
                    text: wordParagraph.expressionLaTex,
                    externalData: {
                        laTex: wordParagraph.expressionLaTex,
                    }
                }
                docItemList.push(tempLaTexDocItem);
                break;
            default:
                break;
        }
    })
    return docItemList;
}

/**
 * 更新docItem的plainText
 * @param docItem 
 * @returns 
 */
const updateDocItemPlainText = (docItem: DocItem) => {
    const { text, textStyleMap } = docItem;
    let updatedPlainText = text;
    Object.entries(textStyleMap).forEach(([key, value]) => {
        updatedPlainText = updatedPlainText.replace(key, value.text);
    });
    docItem.plainText = updatedPlainText;
    return docItem;
}

/**
 * 
 * @param titleLevel 
 * @returns 
 */
const getTitleDocItemType = (titleLevel: number): DocItemType => {
    switch (titleLevel) {
        case 1:
            return DocItemType.H1;
            break;
        case 2:
            return DocItemType.H2;
            break;
        case 3:
            return DocItemType.H3;
            break;
        case 4:
            return DocItemType.H4;
            break;
        case 5:
            return DocItemType.H5;
            break;
        case 6:
            return DocItemType.H6;
            break;
        default:
            return DocItemType.H6;
            break;
    }
}

export {
    generateDocItemId,
    generateDocInstance,
    getRadomParagraphPlainText,
    getReplacedDocInfoPlainText,
    checkDocItemIsTitleParagraph,
    processDocInstanceBeforeUpdate,
    getSlateEditorInputInfoByInputData,
    translateDocInstanceToSlateEditorData,
    translateSlateEditorDataToDocInstance,
    mergeNewSlateEditorInputValueToDocItemList,
    getChangedSlateEditorDocItemList,
    convertWordParagraphListToDocItemList,
    updateDocItemPlainText,
    getTitleDocItemType,
    sortTextStyleMapAndFindMaxIndex
}